#!/bin/bash

#set -x -v
if ! egrep -q "Debian GNU/Linux (5.0|squeeze)" /etc/issue ; then echo "This doesn't look like Lenny or Squeeze. Stopping." && exit 0 ; fi
if [[ $PWD == "/" ]] ; then echo "Do the install from the source directory. Fix and run again." && exit 0  ; fi

unset debian_version
debian_version=$(grep -o squeeze /etc/issue)
if [[ -z $debian_version ]] ; then debian_version="lenny"; fi

packages_needed=0
for i in incron ipcalc iproute dnsmasq lighttpd sudo nmap logrotate vnstat squid resolvconf openntpd ntpdate mtr-tiny dnsutils openssh-client openssh-server
## openssh-client and openssh-server are not needed but very useful
do 
  if [[ ! $( dpkg -s $i | grep ^Status ) =~ ^"Status: install ok installed" ]]
   then echo "Package $i missing." && missing_list="$i ""$missing_list" && packages_needed=1 
  fi
done

if ((packages_needed))
  then echo "Need to aptitude update and  aptitude install $missing_list. Go ahead? [y]"
       read yesno
       if [[ $yesno =~ (n|N) ]]
         then exit 0
       else
         aptitude update; aptitude install $missing_list
       fi
fi



## for squid at least:
( grep ^127.0.0.1 /etc/hosts | awk '{print $3}' | grep -q \. ) || {
  echo "Need an fqdn in /etc/hosts"
  echo 'Eg: modify: 127.0.0.1 localhost ---> 127.0.0.1 localhost '$(hostname)'.local'
  echo "Fix and run again"
  exit 0
}


function mkdir_if_not_there {
if [[ ! -d $1 ]] ; then ( mkdir $1 && echo "created $1" ) ; fi
}

mkdir_if_not_there "/var/log/muggles"
mkdir_if_not_there '/etc/muggles'



NUMBER_OF_UPLINKS=$(ip link show | sed -e 's/[0-9][0-9]*: eth\([0-9][0-9]*\): <BROADCAST,MULTICAST.*/\1/' -e '$!{h;d;}' -e x)
## ... <BROADCAST,MULTICAST,UP,LOWER_UP>.*/\1/'...   if they are up


whiptail --msgbox "           T H E    I N T E R N E T  
            |        |           |
    uplink1 gw1   uplink2 gw2   ....
            |        |           |
          (eth1)   (eth2)      (etc...)
            |        |           |
            ---- muggles box ----
                     |
                   (eth0)
                     |
  ------------------LAN------------------- ...
 |       |                |        |       ...


You need to put in these IP addresses (in CIDR notation):

0. For eth0 (the LAN facing interface)
1. For eth1 (the first uplink-facing interface).
   Also for the gateway used by the first uplink.
2. For eth2 (the second uplink-facing interface).
   Also for the gateway used by the second uplink.
3.  ...etc " 28 68



input_lookover_input_ok=0
until (( $input_lookover_input_ok )) ;
do
  
  
  
  for (( i=0;i<=$NUMBER_OF_UPLINKS;i++)); do
    cidr_ip_eth[i]=$(</etc/muggles/cidr_ip_eth$i)
    gw_ip_eth[i]=$(</etc/muggles/gw_ip_eth$i)
  
  
  
    input_ok=0
    until (( $input_ok )) ;
    do
      cidr_ip_eth[i]=$(
                       whiptail --title "eth$i"\
                                --inputbox  "ip/network (cidr notation) for eth$i. Eg: 192.168.$i.12/24"\
                                10 80 ${cidr_ip_eth[i]} 2>&1 >/dev/tty
                      )
      echo ${cidr_ip_eth[i]} | grep -q -o '^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}/[0-9]\{1,2\}$' && input_ok=1
    done
    echo ${cidr_ip_eth[i]} >/etc/muggles/cidr_ip_eth$i
  
  
  
    if (( i>0 )); then
    input_ok=0
    until (( $input_ok )) ;
    do
      gw_ip_eth[i]=$(
                     whiptail --title "gateway used by ${cidr_ip_eth[i]}."\
                     --inputbox  "gateway address (WITHOUT SUBNET SPECIFICATION) for eth$i."\
                     10 80 ${gw_ip_eth[i]} 2>&1 >/dev/tty
                    )
      echo ${gw_ip_eth[i]} | grep -q -o '^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$' && input_ok=1
    done
    echo ${gw_ip_eth[i]} >/etc/muggles/gw_ip_eth$i
    fi
  
  done
  
  eth0ip=$(echo ${cidr_ip_eth[0]} | cut -f1 -d/)
  netmask[0]=$(ipcalc -n ${cidr_ip_eth[0]} | grep ^Netmask | awk '{print $2}')
  
  ipcalc_hostmin=$(ipcalc -n ${cidr_ip_eth[0]} | grep ^HostMin | awk '{print $2}')
  ipcalc_hostmax=$(ipcalc -n ${cidr_ip_eth[0]} | grep ^HostMax | awk '{print $2}')
  
  input_dns_range_ok=0
  until (( $input_dns_range_ok ))
  do
    dnsmasq_range_lower=$(</etc/muggles/dnsmasq_range_lower)
    input_ok=0
    until (( $input_ok )) ;
    do
      dnsmasq_range_lower=$(
                            whiptail --title "lower ip address in dhcp range (interface ip is $eth0ip)"\
                            --inputbox  "lower ip address (WITHOUT SUBNET SPECIFICATION) in dhcp range (interface ip is $eth0ip)"\
                            10 80 $dnsmasq_range_lower 2>&1 >/dev/tty
                           )
      echo $dnsmasq_range_lower | grep -q -o '^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$' && input_ok=1
    done
    echo $dnsmasq_range_lower >/etc/muggles/dnsmasq_range_lower
  
  
  
    dnsmasq_range_upper=$(</etc/muggles/dnsmasq_range_upper)
    input_ok=0
    until (( $input_ok ))
    do
      dnsmasq_range_upper=$(
                            whiptail --title "upper ip address in dhcp range (interface ip is $eth0ip)"\
                            --inputbox  "upper ip address (WITHOUT SUBNET SPECIFICATION) in dhcp range (interface ip is $eth0ip)"\
                            10 80 $dnsmasq_range_upper 2>&1 >/dev/tty
                           )
      echo $dnsmasq_range_upper | grep -q -o '^[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}$' && input_ok=1
    done
    echo $dnsmasq_range_upper >/etc/muggles/dnsmasq_range_upper
  
  
    function decimate {
                       OLDIFS=$IFS ; IFS="."
                       read h1 h2 h3 h4 <<< "$1"
                       echo $(( h1 * 256 * 256 * 256 + h2 * 256 * 256 + h3 * 256 + h4 ))
                       IFS=$OLDIFS
                      }
  
    eth0ip_decimal=$(decimate $eth0ip)
    dnsmasq_range_lower_decimal=$(decimate $dnsmasq_range_lower)
    dnsmasq_range_upper_decimal=$(decimate $dnsmasq_range_upper)
  
    ipcalc_hostmin_decimal=$(decimate $ipcalc_hostmin)  
    ipcalc_hostmax_decimal=$(decimate $ipcalc_hostmax)  
  
    if [[ (( ipcalc_hostmin_decimal -gt dnsmasq_range_lower_decimal )) || \
          (( ipcalc_hostmax_decimal -lt dnsmasq_range_upper_decimal )) || \
          (( ipcalc_hostmin_decimal -gt dnsmasq_range_upper_decimal )) || \
          (( ipcalc_hostmax_decimal -lt dnsmasq_range_lower_decimal )) ]]
        then whiptail --msgbox "IP range must fit within subnet. Please fix range." 10 50
          ## dnsmasq server can be inside dhcp range without conflict (only downside is that ip is no longer there)
          ## so the check done by the two lines below is not needed.
        ##elif  [[ (( eth0ip_decimal -ge dnsmasq_range_lower_decimal )) && (( eth0ip_decimal -le dnsmasq_range_upper_decimal )) ]]
        ##  then whiptail --msgbox "IP of eth0 must be outside dhcp range. Please fix range." 10 50
    else
      input_dns_range_ok=1
    fi
  done
  
  
  
  lookover=$(
  echo "Does this look ok?"
  echo
  echo "eth0: ${cidr_ip_eth[0]} (lan interface)"
  echo "  lan range $dnsmasq_range_lower - $dnsmasq_range_upper"
  for (( i=1;i<=$NUMBER_OF_UPLINKS;i++)); do
    echo
    echo "eth$i: ${cidr_ip_eth[i]} (uplink $i)"
    echo "gateway: ${gw_ip_eth[i]} (gateway $i)"
  done
  )
  
  whiptail --yesno "$lookover" 28 68 && input_lookover_input_ok=1
done


function package_install {

ts=$(date +%Y%m%d%H%M%S)
package_version="$1"
installed_version="$2"


if [[ -e $package_version ]] ; then
   if [[ -e $installed_version ]] ; then
      if [[ -n $(diff $installed_version $package_version) ]] ; then
         echo "$installed_version which is already installed is going to be changed to the muggles version. Change? [y]" ; read yesno
         if [[ $yesno =~ (n|N) ]] ; then
           echo "Keeping $installed_version. This may break things so the installation will not work."
         else
           ( cp $installed_version "$installed_version"_"$ts" ) && echo "made a backup of the already installed version to ""$installed_version"'_'"$ts"
           ( cp $package_version $installed_version ) && echo "overwrote already installed version $installed_version with muggles version $package_version"
         fi
      else
          echo "$installed_version and $package_version are the same, so changing nothing" 
      fi
   else
      echo "No default already-installed version of $installed_version found. Creating..."
        ( cp $package_version $installed_version ) && echo "created $installed_version"
   fi
else
   echo "No $package_version (package version) file found. So changing nothing."
fi

}



## /etc/
package_install etc/network/if-pre-up.d/masq_ipconf		/etc/network/if-pre-up.d/masq_ipconf

## later, with debconf: user changes interface values

package_install etc/ethers				/etc/ethers
package_install etc/logrotate.d/muggles			/etc/logrotate.d/muggles
package_install etc/init.d/mugglesinit			/etc/init.d/mugglesinit

if [ "$debian_version" = "lenny" ]
  then update-rc.d mugglesinit defaults 41
  else update-rc.d mugglesinit defaults 04
fi

package_install etc/muggles/forced_uplink.conf		/etc/muggles/forced_uplink.conf
chown www-data /etc/muggles/forced_uplink.conf
## also, for sed -i used by machine_settings.cgi, (which needs to be able to write a temp file in directory):
chgrp www-data /etc/muggles ; chmod g+w /etc/muggles

package_install etc/muggles/pinglogger.conf		/etc/muggles/pinglogger.conf
package_install etc/muggles/rulerunner.conf		/etc/muggles/rulerunner.conf
package_install etc/muggles/showcurrent.conf		/etc/muggles/showcurrent.conf
package_install etc/lighttpd/lighttpd.conf		/etc/lighttpd/lighttpd.conf
lighty-enable-mod cgi ; /etc/init.d/lighttpd restart


## /usr/local/sbin
package_install usr/local/sbin/pinglogger		/usr/local/sbin/pinglogger
package_install usr/local/sbin/rulerunner		/usr/local/sbin/rulerunner
package_install usr/local/sbin/mixed			/usr/local/sbin/mixed
package_install usr/local/sbin/defaultrouting		/usr/local/sbin/defaultrouting

## /usr/lib/cgi-bin

package_install usr/lib/cgi-bin/cgi-test.cgi		/usr/lib/cgi-bin/cgi-test.cgi
package_install usr/lib/cgi-bin/machine_settings.cgi	/usr/lib/cgi-bin/machine_settings.cgi
package_install usr/lib/cgi-bin/mixed.cgi		/usr/lib/cgi-bin/mixed.cgi
package_install usr/lib/cgi-bin/showcurrent.cgi		/usr/lib/cgi-bin/showcurrent.cgi
package_install usr/lib/cgi-bin/shutcommand.cgi		/usr/lib/cgi-bin/shutcommand.cgi
package_install usr/lib/cgi-bin/switchisps.cgi		/usr/lib/cgi-bin/switchisps.cgi

chown www-data.www-data /usr/lib/cgi-bin/*

## /var/www/

package_install var/www/background.gif			/var/www/background.gif
package_install var/www/button-a.gif			/var/www/button-a.gif
package_install var/www/button.gif			/var/www/button.gif 
package_install var/www/favicon.ico			/var/www/favicon.ico 
package_install var/www/index.html			/var/www/index.html
package_install var/www/index.lighttpd.html		/var/www/index.lighttpd.html
package_install var/www/output.html			/var/www/output.html
package_install var/www/shutdown.html			/var/www/shutdown.html
package_install var/www/switched.html			/var/www/switched.html

chown www-data.www-data /var/www/*


## incron

( grep -q ^root$ /etc/incron.allow ) || { echo root >> /etc/incron.allow ; }

## need to check preexistence

if [[ $(incrontab -l) =~ '/var/lib/misc/dnsmasq.leases IN_MODIFY,IN_NO_LOOP /usr/local/sbin/rulerunner $@' ]]
   then echo "have a matching incron line, so changing nothing" 
   else
   echo "installing line into incrontab"
   ( incrontab -l
cat<<incrontab_add
/var/lib/misc/dnsmasq.leases IN_MODIFY,IN_NO_LOOP /usr/local/sbin/rulerunner \$@
incrontab_add
) | incrontab -
fi


## sudoers

this_host=$(hostname)

## add these lines to sudoers after checks

ARRAY=(\
"www-data        $this_host= NOPASSWD: /sbin/shutdown" \
"www-data        $this_host= NOPASSWD: /sbin/ip" \
"www-data        $this_host= NOPASSWD: /usr/bin/nmap" \
"www-data        $this_host= NOPASSWD: /usr/local/sbin/mixed" \
"www-data        $this_host= NOPASSWD: /sbin/iptables"\
)

while [[ -e /etc/sudoers.tmp ]] ; do ( echo "sudoers.tmp exists - is sudoers being edited already? If so, fix it then continue by pressing enter"  ; read ) ; done

touch /etc/sudoers.tmp

ELEMENTS=${#ARRAY[@]}

for (( i=0;i<$ELEMENTS;i++)); do
if ( grep ^"${ARRAY[${i}]}" /etc/sudoers 2>&1 >/dev/null ) 
   then echo "have a matching line for ${ARRAY[${i}]} in sudoers, so changing nothing" 
   else
   ( 
cat<<sudoer_add
${ARRAY[${i}]}
sudoer_add
) >> /etc/sudoers
fi
done

rm /etc/sudoers.tmp



## bandwidthd
if [[ -e /etc/bandwidthd/bandwidthd.conf ]] ; then
  if [[ -L /var/www/bandwidthd ]] ; then echo "have a symlink bandwidthd already so changing nothing"
                                    else ln -s /var/lib/bandwidthd/htdocs/ /var/www/bandwidthd && echo 'made symlink /var/lib/bandwidthd/htdocs -> /var/www/bandwidthd'
  fi
fi


configfile_modify () {
    appendstring="$1" ; stringstart="$2" ; insertionpointstring="$3" ; configfile_name="$4"
    ( grep -v ^# $configfile_name | grep ^"$stringstart" ) 2>&1 > /dev/null && \
    sed -i "s/^$stringstart.*$/$stringstart$appendstring/" $configfile_name ||\
    sed -i "s/^\($insertionpointstring\)$/\1\n$stringstart$appendstring\n/" $configfile_name
  }


## squid

sqcf='/etc/squid/squid.conf'

if [[ -e ${sqcf} ]] ; then
     cp ${sqcf} ${sqcf}_${ts}

     ournetwork=$( ipcalc ${cidr_ip_eth[0]} -n  | grep ^Network | awk {'print $2'} | sed 's/\//\\\//')
     configfile_modify ''	"acl our_networks src $ournetwork"	'http_access allow localhost'		${sqcf}
     configfile_modify ''	"http_access allow our_networks"	"acl our_networks src $ournetwork"	${sqcf}

     configfile_modify ''	"http_port 127.0.0.1:3128 transparent"	"http_port 3128"			${sqcf}
     sed -i "s/^\(http_port 3128$\)/#\1/" ${sqcf}

     configfile_modify ''	"http_port $eth0ip:3128 transparent"	"http_port 127.0.0.1:3128 transparent"	${sqcf}

     visname=$( grep ^127.0.0.1 /etc/hosts | awk '{print $3}' | grep \. )
     configfile_modify ''	"visible_hostname $visname"		"http_port $eth0ip:3128 transparent"	${sqcf}
fi

## the above patches original squid.conf typically like this

## < acl our_networks src 192.168.0.0/24
## < http_access allow our_networks
## < 

## < #http_port 3128
## < http_port 127.0.0.1:3128 transparent
## < http_port 192.168.0.12:3128 transparent
## < visible_hostname lennygwbox.local
## < 
## ---
## > http_port 3128
## 


## vnstat
## Gather vnstat data for interfaces except eth0. (initializes database gathering if it isn't already in place. Updates if it is already there)
for (( i=1;i<=$NUMBER_OF_UPLINKS;i++)); do vnstat -u -i eth$i ; echo "vnstat running for $i" ; done

## lighttpd
lhtc='/etc/lighttpd/lighttpd.conf'

if [[ -e $lhtc ]]
  then sed -i "s/^\$HTTP\[\"host\"\].*\"\([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)\".*$/\$HTTP[\"host\"] =~ \"$eth0ip\" {/" $lhtc
  sed -i -r 's@(^include_shell "/usr/share/lighttpd/use-ipv6.pl")@#\1@' $lhtc
  ## bug #560837 workaround
fi

/etc/init.d/lighttpd restart


## openntpd
ntpc='/etc/openntpd/ntpd.conf'
if [[ -e $ntpc ]] 
  then ( grep -v ^# $ntpc | grep ^'listen on' ) 2>&1 > /dev/null && \
  sed -i "s/^listen on \([0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\)$/listen on $eth0ip/" $ntpc || \
  sed -i "s/^#listen on ::1/#listen on ::1\nlisten on $eth0ip/" $ntpc
fi



## dnsmasq
dmcf='/etc/dnsmasq.conf'
if_dns_nameservers=$eth0ip' 8.8.8.8 208.67.220.220'

#$dnsmasq_range_lower $dnsmasq_range_upper

if [[ -e $dmcf ]] ; then 
  cp ${dmcf} ${dmcf}_${ts}
  configfile_modify 'eth0'								'interface='				'#interface='								$dmcf
  configfile_modify ''									'read-ethers'				'#read-ethers'								$dmcf
  configfile_modify "$dnsmasq_range_lower,$dnsmasq_range_upper,${netmask[0]},12h"	'dhcp-range='				'#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h'		$dmcf
  configfile_modify "$eth0ip"								'dhcp-option=option:router,'		'#dhcp-option=option:router,1.2.3.4'					$dmcf
  configfile_modify $(echo $if_dns_nameservers | tr ' ' ',')				'dhcp-option=option:dns-server,'	'#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com'	$dmcf
  configfile_modify "$eth0ip"								'dhcp-option=option:ntp-server,'	'#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5'			$dmcf
fi


## /etc/network/interfaces

eth_list=$(for (( i=0;i<=$NUMBER_OF_UPLINKS;i++)); do echo -n " eth$i"; done)
nwif='/etc/network/interfaces'

echo "# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug${eth_list}

iface eth0 inet static
  address $eth0ip
  netmask ${netmask[0]}
  dns-nameservers $if_dns_nameservers
" > /tmp/interfaces_$ts

for (( i=1;i<=$NUMBER_OF_UPLINKS;i++ )); do
  ethip=$(echo ${cidr_ip_eth[$i]} | cut -f1 -d/)
  netmaskquad=$(ipcalc -n ${cidr_ip_eth[i]} | grep ^Netmask | awk '{print $2}')

  if [[ "$i" == "1" ]] ; then
    route_lines='ip route add default via $gateway dev $IFACE table $uplinkname ;\
     ip route add default via $gateway'
  else
    route_lines='ip route add default via $gateway dev $IFACE table $uplinkname'
  fi

  bigstring="iface eth$i inet static
  address $ethip
  netmask $netmaskquad
  up serial=${i}0 ; uplinkname=uplink$i ; gateway=${gw_ip_eth[$i]} ; tablefile=/etc/iproute2/rt_tables"' ;\
     if ! ( grep -v ^# $tablefile | grep -q -x "^$serial        $uplinkname$" ) ;\
     then echo "$serial        $uplinkname" >> $tablefile ;\
     fi ;\
     '"$route_lines"'
  dns-nameservers 8.8.8.8 208.67.220.220
'

  echo "${bigstring}" >> /tmp/interfaces_$ts

done

if [[ -n $(diff /tmp/interfaces_$ts $nwif) ]]
then echo "$nwif is going to be overwritten. A timestamped backup will go in ${nwif}_${ts}. Go ahead? [y]"
  read yesno
  if [[ $yesno =~ (n|N) ]]
    then
       echo "$nwif unchanged. The networking will probably be broken after reboot" ; exit 0
    else
       cp ${nwif} ${nwif}_${ts}
       mv /tmp/interfaces_${ts} ${nwif}
  fi
fi

echo "Reboot now, and if you did everything right it should all just work"

